﻿using ComLib.ComType;
using FluentFTP;
using IUploading;
using LogLib;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Net;
using System.Reflection;
using System.Text;

namespace FTPService_CRJ
{
    public class FTP_CRJUpload : IUpload
    {
        private string _error = "";
        public string ErrorMessage
        {
            get
            {
                return _error;
            }
        }

        private string _appName = Assembly.GetExecutingAssembly().GetName().Name;
        public string InterfaceName
        {
            get
            {
                return _appName;
            }
        }

        public int TimeoutMillisecond
        {
            get;
            set;
        }

        public int ID
        {
            set;
            get;
        }

        public bool Inited
        {
            get;
            private set;
        }

        public bool Closed
        {
            get;
            private set;
        }

        private FTP_CRJOption _option = new FTP_CRJOption();

        private void LoadSettings()
        {
            if (!File.Exists(_option.ConfigFilePath))
            {
                _option.Save();
            }
            else
            {
                _option.Load();
            }
        }

        public FTP_CRJUpload()
        {
            Inited = false;
            Closed = false;
            LoadSettings();
        }

        public FTP_CRJUpload(FTP_CRJOption opt)
        {
            Inited = false;
            Closed = false;
            _option = opt;
        }
     
        public bool Connect()
        {
            using (FtpClient conn = new FtpClient())
            {
                conn.Host = _option.IP;
                conn.Port = _option.Port;
                conn.EncryptionMode = (FtpEncryptionMode)(int)_option.EncryptionMode;
                conn.Credentials = new NetworkCredential(_option.User, _option.GetPassword());
                try
                {
                    conn.Connect();                   
                    Log.WriteAsync("FTP服务器连接成功!");
                    Inited = true;
                    conn.Disconnect();
                    return true;
                }
                catch (TimeoutException)
                {
                    _error = "连接FTP服务器超时!\n请检查主机Host等配置是否正确。";
                    Log.WriteAsync(_error);
                    Inited = false;
                    return false;
                }
                catch(Exception ex)
                {
                    _error = string.Format("连接FTP服务器失败.\n详情:{0}", ex.Message);
                    Log.WriteException(ex.ToString());
                    Log.WriteAsync(_error);
                    Inited = false;
                    return false;
                }
            }
        }

        /// <summary>
        /// 创建远程上传路径
        /// </summary>
        /// <returns></returns>
        private string CreatRemotePathString()
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("/");
            if (!string.IsNullOrEmpty(_option.Folder))
            {
                builder.Append(_option.Folder);
                builder.Append("/");
            }
            switch (_option.DirFormat)
            {
                case DirectoryFormat.EveryDay:
                    builder.Append(System.DateTime.Now.ToString("yyyyMMdd"));
                    builder.Append("/");
                    break;
                case DirectoryFormat.EveryMonth:
                    builder.Append(System.DateTime.Now.ToString("yyyyMM"));
                    builder.Append("/");
                    builder.Append(System.DateTime.Now.ToString("dd"));
                    builder.Append("/");
                    break;
                case DirectoryFormat.None:
                    break;
                default:
                    break;
            }
            return builder.ToString();
        }

        public bool CreatRemotePath(string remoteDirection)
        {
            if(string.IsNullOrEmpty(remoteDirection)
                || remoteDirection.Length == 0
                || remoteDirection.Length == 1)
            {
                return true;
            }
            string direction = remoteDirection;
            if (remoteDirection[remoteDirection.Length - 1] == '/')
            {
                direction = remoteDirection.Remove(remoteDirection.Length - 1);
            }
            using (FtpClient conn = new FtpClient())
            {
                conn.Host = _option.IP;
                conn.Port = _option.Port;
                conn.EncryptionMode = (FtpEncryptionMode)(int)_option.EncryptionMode;
                conn.Credentials = new NetworkCredential(_option.User, _option.GetPassword());
                if (conn.DirectoryExists(direction))
                {
                    conn.Disconnect();
                    return true;
                }
                _error = "";
                try
                {
                    conn.CreateDirectory(direction, true);
                    string strLog = string.Format("创建目录ftp:/{0}{1}成功!", _option.IP, direction);
                    Log.WriteAsync(strLog);
                    conn.Disconnect();
                    return true;
                }
                catch (Exception ex)
                {
                    _error = string.Format("创建目录ftp:/{0}{1}失败! \n异常详情:{2}\n{3}",
                        _option.IP,
                        direction,
                        ex.Message,
                        ex.InnerException);
                    Log.WriteException(ex.ToString());
                    Log.WriteAsync(_error);
                    return false;
                } 
            }
        }

        public bool Login(string inParam, out string outParam)
        {
            outParam = "";
            Log.AddBeginningBoundary();
            return Connect();
        }

        private void TryDeleteFile(string strFile)
        {
            try
            {
                if (File.Exists(strFile))
                {
                    File.Delete(strFile);
                }
            }
            catch (Exception ex)
            {
                Log.WriteAsync(ex.ToString());
            }
        }

        private bool UploadPhoto(string localFile, string remoteDir, string photoName)
        {
            string extension = Path.GetExtension(localFile);
            string remoteFile = remoteDir + photoName + extension;
            bool isOK = false;
            using (FtpClient conn = new FtpClient())
            {
                conn.Host = _option.IP;
                conn.Port = _option.Port;
                conn.EncryptionMode = (FtpEncryptionMode)(int)_option.EncryptionMode;
                conn.Credentials = new NetworkCredential(_option.User, _option.GetPassword());
                try
                {
                    conn.UploadFile(
                        localFile,
                        remoteFile,
                        FtpExists.Overwrite,
                        true,
                        _option.NeedVerify ? FtpVerify.Retry : FtpVerify.None);
                    conn.Disconnect();
                    string strLog = string.Format("本地文件{0}上传至ftp:/{1}{2}成功!", localFile, _option.IP, remoteFile);
                    Log.WriteAsync(strLog);
                    isOK = true;
                }
                catch (TimeoutException ex)
                {
                    _error = "连接FTP服务器超时!\n请检查主机Host等配置是否正确。";
                    Log.WriteException(ex.ToString());
                    Log.WriteAsync(_error);
                    isOK = false;
                }
                catch (Exception ex)
                {
                    _error = string.Format("上传文件至ftp:/{0}{1}失败! \n异常详情:{2}\n{3}",
                        _option.IP,
                        remoteFile,
                        ex.Message,
                        ex.InnerException);
                    Log.WriteException(ex.ToString());
                    Log.WriteAsync(_error);
                    isOK = false;
                }        
            }
            return isOK;
        }

        public void Logout()
        {
            if (!Inited)
            {
                return;
            }
            Closed = true;
            Log.AddEndingBoundary();
        }

        public bool Test(string param, out string outParam)
        {
            outParam = "";
            return true;
        }

  
        public bool Query(string param, out string outParam)
        {
            outParam = "";
            return true;
        }

        public bool Post(string param, out string outParam)
        {
            _error = "";
            outParam = "";
            JObject inParams = JObject.Parse(param);
            try
            {
                string photoName = (string)inParams["PhotoName"];
                string origPhotoPath = (string)inParams["OrigPhotoPath"];
                string destPhotoPath = (string)inParams["DestPhotoPath"];
                string remoteDir = CreatRemotePathString();
                if (!CreatRemotePath(remoteDir))
                {
                    return false;
                }
                switch (_option.CopyOption)
                {
                    case CopyOptions.Both:
                        return UploadPhoto(origPhotoPath, remoteDir, photoName) 
                            && UploadPhoto(destPhotoPath, remoteDir, photoName);                
                    case CopyOptions.Orginal:
                        return UploadPhoto(origPhotoPath, remoteDir, photoName);
                    case CopyOptions.Outcome:
                        return UploadPhoto(destPhotoPath, remoteDir, photoName);
                    default:
                        return true;
                }
            }
            catch (Exception ex)
            {
                _error = "FTP上传发生了异常, 异常详情: " + ex.Message;
                Log.WriteAsync(_error);
                Log.WriteException(ex.ToString());
                return false;
            }    
        }

        public void ShowConfigDialog(string inParam)
        {
            FormFTPOption form = new FormFTPOption();
            if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                _option = form.Option;
            }
        }
    }
}
